package frobagroup.filter;


import frobagroup.filter.JwtException.AuthenticationException;
import frobagroup.filter.JwtException.NoneAuthTokenException;
import frobagroup.utils.Constants;
import frobagroup.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.joda.time.DateTime;
import org.joda.time.Hours;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

/**
 * Created by Tinsley on 2016/11/22.
 */
public class JwtFilter implements Filter {

    private JwtUtil jwtUtil;
    private List<String> apiWhiteList;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        try {
            this.jwtUtil = WebApplicationContextUtils
                    .getRequiredWebApplicationContext(
                            filterConfig.getServletContext()).getBean(
                            JwtUtil.class);
            this.apiWhiteList = WebApplicationContextUtils
                    .getRequiredWebApplicationContext(
                            filterConfig.getServletContext()).getBean(
                            WhiteList.class).getWhiteList();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doFilter(final ServletRequest req,
                         final ServletResponse res,
                         final FilterChain chain) throws IOException, ServletException {
        final HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        // taking care of CORS
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,userAuth,staffAuth");
        response.setHeader("Access-Control-Allow-Credentials", "true");

        String userAuth = request.getHeader("userAuth");
        String staffAuth = request.getHeader("staffAuth");
        String uri = request.getRequestURI();
        String method = request.getMethod();
        try {
            tokenFilter(uri, userAuth, chain, request, response, method,staffAuth);
            chain.doFilter(request, response);
        } catch (AuthenticationException e) {
            //e.printStackTrace();
            JwtUtil.setPrintWriter(e.getErrorCode(), response, e.getMessage());
        } catch (ServletException e) {
            JwtUtil.setPrintWriter(500, response, e.getMessage());
        }
    }

    @Override
    public void destroy() {

    }

    private void tokenFilter(String uri, String authorization, FilterChain chain, HttpServletRequest request,
                             HttpServletResponse response, String method,String staffAuth)
            throws IOException, ServletException, AuthenticationException {
        /* whiteList uri */
        boolean doFilter = true;
        String remoteAdd = request.getRemoteAddr();
        for (String str : apiWhiteList) {
            if (uri.contains(str)) {
                doFilter = false;
                break;
            }
            if (str.endsWith("/")) {
                str = str.substring(0, str.length() - 1);
            }
            if (remoteAdd.contains(str) || request.getLocalAddr().contains(str + "/") || request.getLocalAddr().endsWith(str)) {
                doFilter = false;
                break;
            }
        }

        if (Boolean.logicalAnd(doFilter, !Objects.equals(method, "OPTIONS"))) {
            if (StringUtils.isEmpty(authorization) && StringUtils.isEmpty(staffAuth)) {
                throw new NoneAuthTokenException("Missing Authorization header.", 401);
            } else {

                if (!StringUtils.isEmpty(authorization)){
                    Claims claims = jwtUtil.parseToken(authorization);
                    //时间在24个小时内就放过，否则是拦截，目前暂时放过
                    DateTime setTime = new DateTime(claims.getIssuedAt().getTime());
                    if (Hours.hoursBetween(setTime, new DateTime()).getHours() > Constants.TOKEN_LIFE_CYCLE)
                        throw new NoneAuthTokenException("Invalid Authorization header.", 401);
                    request.setAttribute("id", claims.get("userId"));
                }
                if (!StringUtils.isEmpty(staffAuth)){
                    Claims claims = jwtUtil.parseToken(staffAuth);
                    //时间在24个小时内就放过，否则是拦截，目前暂时放过
                    DateTime setTime = new DateTime(claims.getIssuedAt().getTime());
                    if (Hours.hoursBetween(setTime, new DateTime()).getHours() > Constants.TOKEN_LIFE_CYCLE)
                        throw new NoneAuthTokenException("Invalid Authorization header.", 401);
                    request.setAttribute("staffId", claims.get("staffId"));

                }

            }
        }
    }


}
